/**
 * 音乐目录服务
 *
 * 提供音乐目录的核心业务逻辑，包括目录的CRUD操作以及目录与歌曲、播放列表的关联管理。
 * 所有操作均需要验证用户权限，确保用户只能操作自己的目录。
 */
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { MusicDirectory } from './music-directory.entity';
import { User } from '../user/user.entity';
import { Song } from '../song/song.entity';
import { Playlist } from '../playlist/playlist.entity';
import {
  CreateMusicDirectoryDto,
  UpdateMusicDirectoryDto,
  MusicDirectoryResponseDto,
  AddSongToDirectoryDto,
  AddPlaylistToDirectoryDto,
} from './music-directory.dto';

@Injectable()
export class MusicDirectoryService {
  constructor(
    @InjectRepository(MusicDirectory)
    private musicDirectoryRepository: Repository<MusicDirectory>,
    @InjectRepository(Song) private songRepository: Repository<Song>,
    @InjectRepository(Playlist)
    private playlistRepository: Repository<Playlist>,
  ) {}

  /**
   * 创建新的音乐目录
   *
   * @param user 当前登录用户
   * @param createDto 创建目录的请求数据
   * @returns 创建的目录信息
   */
  async createDirectory(
    user: User,
    createDto: CreateMusicDirectoryDto,
  ): Promise<MusicDirectoryResponseDto> {
    const directory = this.musicDirectoryRepository.create({
      name: createDto.name,
      description: createDto.description,
      owner: user,
    });

    const savedDirectory = await this.musicDirectoryRepository.save(directory);
    return this.mapDirectoryToResponse(savedDirectory);
  }

  /**
   * 获取用户的所有音乐目录
   *
   * @param user 当前登录用户
   * @returns 用户所有目录的列表
   */
  async getUserDirectories(user: User): Promise<MusicDirectoryResponseDto[]> {
    console.log(user);
    const directories = await this.musicDirectoryRepository.find({
      where: { owner: { id: user.id } },
    });
    return directories.map(this.mapDirectoryToResponse);
  }

  /**
   * 获取目录详情
   *
   * @param user 当前登录用户
   * @param directoryId 目录ID
   * @returns 目录详情，包含关联的歌曲和播放列表
   * @throws NotFoundException 当目录不存在或不属于当前用户时抛出
   */
  async getDirectoryById(
    user: User,
    directoryId: number,
  ): Promise<MusicDirectoryResponseDto> {
    const directory = await this.musicDirectoryRepository.findOne({
      where: { id: directoryId, owner: { id: user.id } },
      relations: ['songs', 'playlists'],
    });
    if (!directory) {
      throw new NotFoundException('目录不存在');
    }
    return this.mapDirectoryToResponse(directory);
  }

  /**
   * 更新目录信息
   *
   * @param user 当前登录用户
   * @param directoryId 目录ID
   * @param updateDto 更新目录的请求数据
   * @returns 更新后的目录信息
   * @throws NotFoundException 当目录不存在或不属于当前用户时抛出
   */
  async updateDirectory(
    user: User,
    directoryId: number,
    updateDto: UpdateMusicDirectoryDto,
  ): Promise<MusicDirectoryResponseDto> {
    const directory = await this.musicDirectoryRepository.findOne({
      where: { id: directoryId, owner: { id: user.id } },
    });
    if (!directory) {
      throw new NotFoundException('目录不存在');
    }

    if (updateDto.name) directory.name = updateDto.name;
    if (updateDto.description !== undefined)
      directory.description = updateDto.description;

    const updatedDirectory =
      await this.musicDirectoryRepository.save(directory);
    return this.mapDirectoryToResponse(updatedDirectory);
  }

  /**
   * 删除目录
   *
   * @param user 当前登录用户
   * @param directoryId 目录ID
   * @throws NotFoundException 当目录不存在或不属于当前用户时抛出
   */
  async deleteDirectory(user: User, directoryId: number): Promise<void> {
    const directory = await this.musicDirectoryRepository.findOne({
      where: { id: directoryId, owner: { id: user.id } },
    });
    if (!directory) {
      throw new NotFoundException('目录不存在');
    }

    await this.musicDirectoryRepository.remove(directory);
  }

  /**
   * 向目录添加歌曲
   *
   * @param user 当前登录用户
   * @param directoryId 目录ID
   * @param addSongsDto 要添加的歌曲ID列表
   * @returns 更新后的目录信息
   * @throws NotFoundException 当目录不存在或部分歌曲不存在时抛出
   */
  async addSongsToDirectory(
    user: User,
    directoryId: number,
    addSongsDto: AddSongToDirectoryDto,
  ): Promise<MusicDirectoryResponseDto> {
    const directory = await this.musicDirectoryRepository.findOne({
      where: { id: directoryId, owner: { id: user.id } },
      relations: ['songs'],
    });
    if (!directory) {
      throw new NotFoundException('目录不存在');
    }

    const songs = await this.songRepository.findByIds(addSongsDto.songIds);
    if (songs.length !== addSongsDto.songIds.length) {
      throw new NotFoundException('部分歌曲不存在');
    }

    // 避免重复添加
    const existingSongIds = new Set(directory.songs.map((song) => song.id));
    const newSongs = songs.filter((song) => !existingSongIds.has(song.id));
    directory.songs = [...directory.songs, ...newSongs];

    const updatedDirectory =
      await this.musicDirectoryRepository.save(directory);
    return this.mapDirectoryToResponse(updatedDirectory);
  }

  /**
   * 从目录移除歌曲
   *
   * @param user 当前登录用户
   * @param directoryId 目录ID
   * @param songId 要移除的歌曲ID
   * @returns 更新后的目录信息
   * @throws NotFoundException 当目录不存在时抛出
   */
  async removeSongFromDirectory(
    user: User,
    directoryId: number,
    songId: number,
  ): Promise<MusicDirectoryResponseDto> {
    const directory = await this.musicDirectoryRepository.findOne({
      where: { id: directoryId, owner: { id: user.id } },
      relations: ['songs'],
    });
    if (!directory) {
      throw new NotFoundException('目录不存在');
    }

    directory.songs = directory.songs.filter((song) => song.id !== songId);
    const updatedDirectory =
      await this.musicDirectoryRepository.save(directory);
    return this.mapDirectoryToResponse(updatedDirectory);
  }

  /**
   * 向目录添加播放列表
   *
   * @param user 当前登录用户
   * @param directoryId 目录ID
   * @param addPlaylistsDto 要添加的播放列表ID列表
   * @returns 更新后的目录信息
   * @throws NotFoundException 当目录不存在或部分播放列表不存在时抛出
   */
  async addPlaylistsToDirectory(
    user: User,
    directoryId: number,
    addPlaylistsDto: AddPlaylistToDirectoryDto,
  ): Promise<MusicDirectoryResponseDto> {
    const directory = await this.musicDirectoryRepository.findOne({
      where: { id: directoryId, owner: { id: user.id } },
      relations: ['playlists'],
    });
    if (!directory) {
      throw new NotFoundException('目录不存在');
    }

    const playlists = await this.playlistRepository.findByIds(
      addPlaylistsDto.playlistIds,
    );
    if (playlists.length !== addPlaylistsDto.playlistIds.length) {
      throw new NotFoundException('部分播放列表不存在');
    }

    // 避免重复添加
    const existingPlaylistIds = new Set(
      directory.playlists.map((playlist) => playlist.id),
    );
    const newPlaylists = playlists.filter(
      (playlist) => !existingPlaylistIds.has(playlist.id),
    );
    directory.playlists = [...directory.playlists, ...newPlaylists];

    const updatedDirectory =
      await this.musicDirectoryRepository.save(directory);
    return this.mapDirectoryToResponse(updatedDirectory);
  }

  /**
   * 从目录移除播放列表
   *
   * @param user 当前登录用户
   * @param directoryId 目录ID
   * @param playlistId 要移除的播放列表ID
   * @returns 更新后的目录信息
   * @throws NotFoundException 当目录不存在时抛出
   */
  async removePlaylistFromDirectory(
    user: User,
    directoryId: number,
    playlistId: number,
  ): Promise<MusicDirectoryResponseDto> {
    const directory = await this.musicDirectoryRepository.findOne({
      where: { id: directoryId, owner: { id: user.id } },
      relations: ['playlists'],
    });
    if (!directory) {
      throw new NotFoundException('目录不存在');
    }

    directory.playlists = directory.playlists.filter(
      (playlist) => playlist.id !== playlistId,
    );
    const updatedDirectory =
      await this.musicDirectoryRepository.save(directory);
    return this.mapDirectoryToResponse(updatedDirectory);
  }

  /**
   * 获取目录中的所有歌曲
   *
   * @param user 当前登录用户
   * @param directoryId 目录ID
   * @returns 目录中的歌曲列表
   * @throws NotFoundException 当目录不存在时抛出
   */
  async getDirectorySongs(user: User, directoryId: number): Promise<Song[]> {
    const directory = await this.musicDirectoryRepository.findOne({
      where: { id: directoryId, owner: { id: user.id } },
      relations: ['songs'],
    });
    if (!directory) {
      throw new NotFoundException('目录不存在');
    }
    return directory.songs;
  }

  /**
   * 获取目录中的所有播放列表
   *
   * @param user 当前登录用户
   * @param directoryId 目录ID
   * @returns 目录中的播放列表列表
   * @throws NotFoundException 当目录不存在时抛出
   */
  async getDirectoryPlaylists(
    user: User,
    directoryId: number,
  ): Promise<Playlist[]> {
    const directory = await this.musicDirectoryRepository.findOne({
      where: { id: directoryId, owner: { id: user.id } },
      relations: ['playlists'],
    });
    if (!directory) {
      throw new NotFoundException('目录不存在');
    }
    return directory.playlists;
  }

  /**
   * 将MusicDirectory实体映射为MusicDirectoryResponseDto
   *
   * @param directory 音乐目录实体
   * @returns 格式化后的响应数据
   */
  private mapDirectoryToResponse(
    directory: MusicDirectory,
  ): MusicDirectoryResponseDto {
    return {
      id: directory.id,
      name: directory.name,
      description: directory.description,
      ownerId: directory.owner.id,
      songCount: directory.songs?.length || 0,
      playlistCount: directory.playlists?.length || 0,
      createdAt: directory.createdAt,
      updatedAt: directory.updatedAt,
    };
  }
}
